/*
 * Copyright (C) 2023 razaghimahdi (Mahdi Razzaghi Ghaleh)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.wsl.compose.ui.drawer

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.anchoredDraggable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DrawerValue
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.semantics.dismiss
import androidx.compose.ui.semantics.paneTitle
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.gitee.wsl.common.ui.ext.toDp
import com.gitee.wsl.common.ui.ext.toPx
import com.gitee.wsl.compose.ui.base.Drawer
import kotlinx.coroutines.launch
import kotlin.math.roundToInt


/**
 * @param drawerContent composable that represents content inside the drawer
 * @param modifier optional modifier for the drawer
 * @param drawerState state of the drawer
 * @param gesturesEnabled whether or not drawer can be interacted by gestures
 * @param drawerBackgroundColor background color to be used for the drawer sheet
 * @param drawerContentColor color of the content to use inside the drawer sheet. Defaults to
 * @param contentCornerSize size of shape of the content
 * @param contentBackgroundColor background color to be used for the content
 * @param content content of the rest of the UI
 *
 * @throws IllegalStateException when parent has [Float.POSITIVE_INFINITY] width
 */

@Suppress("UnusedBoxWithConstraintsScope")
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Drawer.Card(
    drawerContent: @Composable ColumnScope.() -> Unit,
    modifier: Modifier = Modifier,
    drawerState: CardDrawerState = rememberCardDrawerState(DrawerValue.Closed),
    gesturesEnabled: Boolean = true,
    drawerBackgroundColor: Color = MaterialTheme.colorScheme.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    screenWidth:Dp = 600.dp,
    contentCornerSize: Dp = 0.dp,
    contentBackgroundColor: Color = MaterialTheme.colorScheme.surface,
    content: @Composable () -> Unit
) {
    val scope = rememberCoroutineScope()

    //val configuration = LocalConfiguration.current
    //val screenWidth = configuration.screenWidthDp.dp.toPx()
    val screenWidth = screenWidth.toPx()
    val endContentXPosition = (screenWidth / ThresholdXPosition).roundToInt()

    BoxWithConstraints(modifier.background(drawerBackgroundColor)) {
        val modalDrawerConstraints = constraints
        // TODO : think about Infinite max bounds case
        if (!modalDrawerConstraints.hasBoundedWidth) {
            throw IllegalStateException("Drawer shouldn't have infinite width")
        }
        val density1 = LocalDensity.current
        val minValue = -modalDrawerConstraints.maxWidth.toFloat()
        val maxValue = 0f
        //val anchors = mapOf(minValue to DrawerValue.Closed, maxValue to DrawerValue.Open)
        val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl


        SideEffect {
            drawerState.density = density1
            drawerState.swipeableState.updateAnchors(
                androidx.compose.foundation.gestures.DraggableAnchors {
                    DrawerValue.Closed at minValue
                    DrawerValue.Open at maxValue
                }
            )
        }

        Box(
            Modifier.anchoredDraggable(
                state = drawerState.swipeableState,
                //anchors = anchors,
                //thresholds = { _, _ -> FractionalThreshold(0.5f) },
                orientation = Orientation.Horizontal,
                enabled = gesturesEnabled,
                reverseDirection = isRtl,
                //velocityThreshold = drawerState.DrawerVelocityThreshold,
                //resistance = null
            )
        ) {

            Surface(
                Modifier
                    .fillMaxHeight()
                    .offset {
                        // IntOffset(drawerState.offset.value.roundToInt(), 0)

                        val x = (drawerState.currentOffset.roundToInt())
                        if (x <= endContentXPosition) {
                            IntOffset(x, 0)
                        } else {
                            IntOffset(endContentXPosition, 0)
                        }

                    }
                    .width(endContentXPosition.toDp())
                    .widthIn(0.dp, endContentXPosition.toDp())
                    .semantics {
                        paneTitle = "FullDrawerLayout"
                        if (drawerState.isOpen) {
                            dismiss {
                                if (drawerState.currentValue == DrawerValue.Closed) {
                                    scope.launch { drawerState.close() }
                                };true
                            }
                        }
                    },
                color = drawerBackgroundColor,
                contentColor = drawerContentColor
            ) {
                Column(content = drawerContent)
            }

            Surface(
                Modifier
                    .fillMaxSize()
                    .offset {
                        val x = (drawerState.currentOffset.roundToInt() + screenWidth)
                        if (x <= endContentXPosition) {
                            IntOffset(x, 0)
                        } else {
                            IntOffset(endContentXPosition, 0)
                        }
                    }
                    .graphicsLayer {
                        rotationY =
                            (-((ThresholdYRotation * (drawerState.currentOffset / screenWidth)) + ThresholdYRotation))
                        cameraDistance = ThresholdCameraDistance * density
                    },
                color = contentBackgroundColor,
                shape = RoundedCornerShape(((contentCornerSize.value * (drawerState.currentOffset / screenWidth)) + contentCornerSize.value).roundToInt().dp)
            ) {
                content()
            }

        }
    }
}


private const val ThresholdXPosition = 1.4f
private const val ThresholdYRotation = 25
private const val ThresholdCameraDistance = 8